use clap::Parser;
use std::fs;
use std::io;
mod generators;
mod processor;

/// Arguments provided to the cli program.
#[derive(Parser, Debug, Clone)]
#[clap(about, version, author)]
struct Args {
    /// File to parse
    file: String,

    /// Output file
    #[clap(short, long)]
    output: Option<String>,

    /// Type of generator
    #[clap(arg_enum, short, long)]
    generator: Option<generators::InbuiltGenerators>,
}

impl Args {
    /// Gets generator as box, without printing if generator == None.
    fn get_generator_quiet(&self) -> Box<dyn generators::Generator> {
        match self.generator {
            Some(generators::InbuiltGenerators::HTML) => Box::new(generators::HtmlGenerator::new()),
            Some(generators::InbuiltGenerators::ANSI) => Box::new(generators::AnsiGenerator::new()),
            None => Box::new(generators::AnsiGenerator::new()),
        }
    }

    /// Gets the generator supplied as a box.
    pub fn get_generator(&self) -> Box<dyn generators::Generator> {
        if let None = self.generator {
            eprintln!("Using ANSI Generator by default!");
        }

        self.get_generator_quiet()
    }

    /// gets the output file provided by user.
    pub fn get_output_file(&self) -> String {
        match self.output.clone() {
            Some(s) => s,
            None => format!(
                "{}{}",
                self.get_file_name(),
                self.get_generator_quiet().output_file_ext()
            ),
        }
    }

    /// Gets the file name **without** extension
    pub fn get_file_name(&self) -> String {
        if let Some(name) = self.file.split(".").next() {
            name.to_string()
        } else {
            self.file.clone()
        }
    }
}

fn main() -> io::Result<()> {
    let args = Args::parse();

    // input and output files
    let in_file = &args.file;
    let out_file = args.get_output_file();

    let tokens = processor::DocToken::from_file(in_file.as_str());

    // gets generator to use
    let mut generator = args.get_generator();
    let out_str = generator.generate(&tokens) + "\n";

    fs::write(out_file, out_str)?;

    Ok(())
}
